package gae.testjig.client;

import java.util.List;

import gae.testjig.client.ChannelProvider.ChannelReady;
import gae.testjig.client.ChannelProvider.ClientChannel;
import gae.testjig.client.UIFeedbackLabel.FeedbackListener;
import gae.testjig.client.eventbus.ChannelMetaEvent;
import gae.testjig.client.eventbus.CommandReadyEvent;
import gae.testjig.client.eventbus.EchoEvent;
import gae.testjig.client.eventbus.InfoEvent;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiConstructor;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.SimpleEventBus;

public class UIConstraintTest extends Composite {

	interface UIConstraintTestUiBinder extends UiBinder<Widget, UIConstraintTest> {}
	private static UIConstraintTestUiBinder uiBinder = GWT.create(UIConstraintTestUiBinder.class);

	@UiField Button btnEchoChannel;
	@UiField Button btnAlice;
	@UiField Button btnBob;
	@UiField Button btnReset;
	@UiField Button btnFetch;
	@UiField Button btnRace;
	@UiField Button btnRaceOfy;
	@UiField Button btnClearLog;
	@UiField UIFeedbackLabel lblFeedback;
	@UiField HTML txtConsoleLog;
	
	private String seatId = "seat-" + Random.nextInt(1000000);

	@UiConstructor
	public UIConstraintTest(final GaeTestJigServiceAsync SERVICE, final ClientChannel cp, final SimpleEventBus eventBus) {
		initWidget(uiBinder.createAndBindUi(this));
		
		ChannelMetaEvent.register(eventBus, new ChannelMetaEvent.Handler() {
			@Override
			public void onFeedback(String message) {
				lblFeedback.setTextNoSpin(message);
			}
		});
		EchoEvent.registerToSource(eventBus, cp.getClientChannelId(), new EchoEvent.Handler() {
			@Override
			public void onEcho(EchoEvent event) {
				lblFeedback.setTextNoSpin(event.getMessage());
			}
		});
		InfoEvent.registerToSource(eventBus, cp.getClientChannelId(), new InfoEvent.Handler() {
			@Override
			public void onInfo(InfoEvent event) {
				lblFeedback.setTextNoSpin(event.getMessage());
			}
		});
		CommandReadyEvent.registerToSource(eventBus, cp.getClientChannelId(), new CommandReadyEvent.Handler() {
			@Override
			public void onReady(String message) {
				if ( "reset".equals(message) ) {
					btnReset.setEnabled(true);
					btnAlice.setEnabled(true);
					btnBob.setEnabled(true);
					btnRace.setEnabled(true);
					btnRaceOfy.setEnabled(true);
				}
				else if ( "Alice".equals(message) ) {
					btnAlice.setEnabled(true);
				}
				else if ( "Bobby".equals(message) ) {
					btnBob.setEnabled(true);
				}
			}
		});

		lblFeedback.addFeedbackListener(new FeedbackListener() {
			@Override
			public void onFeedback(String message) {
				append(message);
			}
		});

		btnEchoChannel.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				cp.ensureOpenChannel(new ChannelReady() {
					@Override
					public void onChannelReady() {
						SERVICE.sendEchoChannel(cp.getClientChannelId(), new AsyncCallback<Void>() {
							@Override
							public void onSuccess(Void result) {
							}
							@Override
							public void onFailure(Throwable caught) {
								lblFeedback.setTextNoSpin(caught.getMessage());
							}
						});
					}
				});
			}
		});

		btnClearLog.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				clearLog();
			}
		});
		
		
		btnAlice.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				cp.ensureOpenChannel(new ChannelReady() {
					@Override
					public void onChannelReady() {
						btnAlice.setEnabled(false);
						SERVICE.doConstraintTest(cp.getClientChannelId(), "Alice", seatId, new AsyncCallback<Boolean>() {
							@Override
							public void onSuccess(Boolean accepted) {
								if ( ! accepted ) {
									btnAlice.setEnabled(true);
								}
							}
							@Override
							public void onFailure(Throwable caught) {
								lblFeedback.setTextNoSpin(caught.getMessage());
								btnAlice.setEnabled(true);
							}
						});
					}
				});
			}
		});

		btnBob.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				cp.ensureOpenChannel(new ChannelReady() {
					@Override
					public void onChannelReady() {
						btnBob.setEnabled(false);
						SERVICE.doConstraintTest(cp.getClientChannelId(), "Bobby", seatId, new AsyncCallback<Boolean>() {
							@Override
							public void onSuccess(Boolean accepted) {
								if ( ! accepted ) {
									btnBob.setEnabled(true);
								}
							}
							@Override
							public void onFailure(Throwable caught) {
								lblFeedback.setTextNoSpin(caught.getMessage());
								btnBob.setEnabled(true);
							}
						});
					}
				});
			}
		});
		
		btnRace.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				cp.ensureOpenChannel(new ChannelReady() {
					@Override
					public void onChannelReady() {
						btnRace.setEnabled(false);
						String[] ownerNames = {"Alice", "Bobby"};
						SERVICE.doRace(cp.getClientChannelId(), ownerNames, seatId, new AsyncCallback<Void>() {
							@Override
							public void onSuccess(Void result) {
							}
							@Override
							public void onFailure(Throwable caught) {
								lblFeedback.setTextNoSpin(caught.getMessage());
								btnRace.setEnabled(true);
							}
						});
					}
				});
			}
		});
		
		btnRaceOfy.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				cp.ensureOpenChannel(new ChannelReady() {
					@Override
					public void onChannelReady() {
						btnRaceOfy.setEnabled(false);
						String[] ownerNames = {"Alice", "Bobby"};
						SERVICE.doRaceObjectify(cp.getClientChannelId(), ownerNames, seatId, new AsyncCallback<Void>() {
							@Override
							public void onSuccess(Void result) {
							}
							@Override
							public void onFailure(Throwable caught) {
								lblFeedback.setTextNoSpin(caught.getMessage());
								btnRaceOfy.setEnabled(true);
							}
						});
					}
				});
			}
		});
		
		btnReset.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				cp.ensureOpenChannel(new ChannelReady() {
					@Override
					public void onChannelReady() {
						btnReset.setEnabled(false);
						String[] names = {"Alice","Bobby"};
						SERVICE.resetConstraintTest(cp.getClientChannelId(), names, seatId, new AsyncCallback<Void>() {
							@Override
							public void onSuccess(Void result) {
							}
							@Override
							public void onFailure(Throwable caught) {
								lblFeedback.setTextNoSpin(caught.getMessage());
								btnReset.setEnabled(true);
							}
						});
					}
				});
			}
		});
		
		btnFetch.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				cp.ensureOpenChannel(new ChannelReady() {
					@Override
					public void onChannelReady() {
						SERVICE.fetchSeatInfo(cp.getClientChannelId(), seatId, new AsyncCallback<Void>() {
							@Override
							public void onSuccess(Void result) {
							}
							@Override
							public void onFailure(Throwable caught) {
								lblFeedback.setTextNoSpin(caught.getMessage());
							}
						});
					}
				});
			}
		});

	}

	public void append(List<String> list) {
		for ( String msg : list ) {
			append(msg);
		}
	}	
	
	public void append(String msg) {
		String content = txtConsoleLog.getHTML();
		txtConsoleLog.setHTML(content + msg + "<br/>");
		txtConsoleLog.getElement().setScrollTop(txtConsoleLog.getElement().getScrollHeight()); // keep scrolled to bottom
	}
	
	public void clearLog() {
		txtConsoleLog.setHTML("");
	}

}
